; Copyright 2014 padnest@gmail.com

; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;   http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.


; -------------------------------------------------------------------------------
; Set of macros created to make easy structured programming in MPASM.
; -------------------------------------------------------------------------------
; Verified on MPASM v5.53 
; Please send any feedback to padnest@gmail.com
; For any update news follow/subscribe to padnest.blogspot.com
; -------------------------------------------------------------------------------
; changelog
;	v1.0 (2014-01-16) - initial release
; -------------------------------------------------------------------------------


; comparision types to use as cond value
#define EQ 0
#define NE 1
#define GE 2
#define GT 3
#define LE 4
#define LT 5


			variable	_breakCount = 0
			variable	_breakNestedIdx = 0

; -------------------------------------------------------------------------------
; DO-UNTIL
; -------------------------------------------------------------------------------
; Begin loop:	do
;   End loop:	forever, untilfl, untilff, untilfset, untilfclr
;  Exit loop:	break, exitdo
; -------------------------------------------------------------------------------
			variable	_doBlockCount = 0
			variable	_doNestedIdx = 0
; -------------------------------------------------------------------------------
; DO
; -------------------------------------------------------------------------------
; Syntax:		do
; Description: 	Executes a block of instrucions until the condition, specified
;				at the close, holds.
; Affected:		none
; -------------------------------------------------------------------------------
do			macro
_doBlockCount ++
_doNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_do#v(_doBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_doNested#v(_doNestedIdx) = _doBlockCount
			endm

; -------------------------------------------------------------------------------
; DO - EXITDO
; -------------------------------------------------------------------------------
; Syntax:		exitdo
; Description:  Exit from the innermost do block.
; Affected:		none
; -------------------------------------------------------------------------------
exitdo		macro
			goto	_enddo#v(_doNested#v(_doNestedIdx))
			endm

; -------------------------------------------------------------------------------
; DO - FOREVER
; -------------------------------------------------------------------------------
; Syntax:		forever
; Description:	Always jump at the top of the loop.
; Affected:		none
; -------------------------------------------------------------------------------
forever		macro
			goto	_do#v(_doNested#v(_doNestedIdx))
_enddo#v(_doNested#v(_doNestedIdx))
_doNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm

; -------------------------------------------------------------------------------
; DO - UNTILFL
; -------------------------------------------------------------------------------
; Syntax:		untilfl freg, cond, lit
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the literal value to compare
; Description:	Performs a comparison between freg and lit.
; 				If matches the loop terminates.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
untilfl		macro	freg, cond, lit
		if (cond == EQ)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto	_do#v(_doNested#v(_doNestedIdx))
_enddo#v(_doNested#v(_doNestedIdx))
_doNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm

; -------------------------------------------------------------------------------
; DO - UNTILFF
; -------------------------------------------------------------------------------
; Syntax:		untilff freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Description:	Performs a comparison between freg1 and freg2 values.
;				If matches the loop terminates.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
untilff		macro	freg1, cond, freg2
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)			
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)					
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else					
		if (cond == GT)			
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto	_do#v(_doNested#v(_doNestedIdx))
_enddo#v(_doNested#v(_doNestedIdx))
_doNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm

; -------------------------------------------------------------------------------
; DO - UNTILFSET
; -------------------------------------------------------------------------------
; Syntax:		untilfset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	freg selection type: ACCESS or BANKED
; Description:	Tests the specified bit of freg and terminates
; 				loop execution if it is set.
; Affected:		none
; -------------------------------------------------------------------------------
untilfset	macro	freg, bit, fregsel
			btfss	freg, bit, fregsel
			goto	_do#v(_doNested#v(_doNestedIdx))
_enddo#v(_doNested#v(_doNestedIdx))
_doNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm

; -------------------------------------------------------------------------------
; DO - UNTILFCLR
; -------------------------------------------------------------------------------
; Syntax:		untilfclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	freg selection type: ACCESS oer BANKED
; Description:  Tests the specified bit of freg and terminates
;				loop execution if it is clear.
; Affected:		none
; -------------------------------------------------------------------------------
untilfclr	macro	freg, bit, fregsel
			btfsc	freg, bit, fregsel
			goto	_do#v(_doNested#v(_doNestedIdx))
_enddo#v(_doNested#v(_doNestedIdx))
_doNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm


; -------------------------------------------------------------------------------
; FOR-NEXT
; -------------------------------------------------------------------------------
; Begin loop:	for
;   End loop:	next, nextl
;  Exit loop:	break, exitfor
; -------------------------------------------------------------------------------
			variable	_forBlockCount = 0
			variable	_forNestedIdx = 0
; -------------------------------------------------------------------------------
; FOR
; -------------------------------------------------------------------------------
; Syntax:		for freg, startl, endl
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be used as count variable
;				startl 	a literal value used as the initial value of the count
;				endl	a literal value used as the final value of the count
; Description:	Executes the for-next block until the value of freg exceeds the endl
;				value.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
for			macro		freg, startl, endl
_forBlockCount ++
_forNestedIdx ++
_breakCount ++
_breakNestedIdx ++
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_forNested#v(_forNestedIdx) = _forBlockCount
			movlw		startl
			movwf		freg, BANKED
_for#v(_forBlockCount)
			movf		freg, W, BANKED
			sublw		endl
			btfss		STATUS, C, ACCESS
			goto		_endfor#v(_forBlockCount)
			endm

; -------------------------------------------------------------------------------
; FOR - EXITFOR
; -------------------------------------------------------------------------------
; Syntax:		exitfor
; -------------------------------------------------------------------------------
; Description:	Exits from the innermost for-next block.
; Affected:		none
; -------------------------------------------------------------------------------
exitfor		macro
			goto	_endfor#v(_forNested#v(_forNestedIdx))
			endm

; -------------------------------------------------------------------------------
; FOR - NEXT
; -------------------------------------------------------------------------------
; Syntax:		next freg
; -------------------------------------------------------------------------------
; Arguments:	freg	the register being used as the loop count variable
; Description:	Increments the freg and jumps to the top of the for loop.
; Affected:		freg, STATUS
; -------------------------------------------------------------------------------
next		macro		freg
			incf		freg, F, BANKED
			goto		_for#v(_forNested#v(_forNestedIdx))
_endfor#v(_forNested#v(_forNestedIdx))
_forNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm

; -------------------------------------------------------------------------------
; FOR - NEXTL
; -------------------------------------------------------------------------------
; Syntax:		nextl freg, stepl
; -------------------------------------------------------------------------------
; Arguments:	freg	the register being used as the loop count variable
; Description:	Increments the freg by stepl value and jumps to the top
;				of the loop.
; Affected:		freg, W, STATUS
; -------------------------------------------------------------------------------
nextl		macro		freg, stepl
			movf		freg, W, BANKED
			addlw		stepl
			movwf		freg, BANKED
			goto		_for#v(_forNested#v(_forNestedIdx))
_endfor#v(_forNested#v(_forNestedIdx))
_forNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm



; -------------------------------------------------------------------------------
; IF - ENDI
; -------------------------------------------------------------------------------
; Begin block:	ifl, iff, ifset, ifclr,
;   End block:	endi
;      Inners:	andifl, andiff, andifset, andifclr,
;				orifl, oriff, orifset, orifclr,
;				elseifl, elseiff, elseifset, elseifclr, otherwise
; -------------------------------------------------------------------------------
			variable	_ifBlockCount = 0
			variable	_ifNestedIdx = 0
; -------------------------------------------------------------------------------
; IF - IFL
; -------------------------------------------------------------------------------
; Syntax:		ifl freg, cond, lit
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the literal value to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
ifl			macro		freg, cond, lit
_ifBlockCount ++
_ifNestedIdx ++
			variable	_ifNested#v(_ifNestedIdx) = _ifBlockCount
			variable	_ifcaseNested#v(_ifNestedIdx) = 1
_if#v(_ifBlockCount)
		if (cond == EQ)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg ,W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto	_if#v(_ifBlockCount)_ifcase1
			endm

; -------------------------------------------------------------------------------
; IF - IFF
; -------------------------------------------------------------------------------
; Syntax:		ifl freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
iff			macro	freg1, cond, freg2
_ifBlockCount ++
_ifNestedIdx ++
			variable	_ifNested#v(_ifNestedIdx) = _ifBlockCount
			variable	_ifcaseNested#v(_ifNestedIdx) = 1
_if#v(_ifBlockCount)
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto	_if#v(_ifBlockCount)_ifcase1
			endm

; -------------------------------------------------------------------------------
; IF - IFSET
; -------------------------------------------------------------------------------
; Syntax:		ifset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
ifset		macro	freg, bit, fregsel
_ifBlockCount ++
_ifNestedIdx ++
			variable	_ifNested#v(_ifNestedIdx) = _ifBlockCount
			variable	_ifcaseNested#v(_ifNestedIdx) = 1
_if#v(_ifBlockCount)
			btfss	freg, bit, fregsel
			goto	_if#v(_ifBlockCount)_ifcase1
			endm

; -------------------------------------------------------------------------------
; IFCLR
; -------------------------------------------------------------------------------
; Syntax:		ifclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
ifclr		macro	freg, bit, fregsel
_ifBlockCount ++
_ifNestedIdx ++
			variable	_ifNested#v(_ifNestedIdx) = _ifBlockCount
			variable	_ifcaseNested#v(_ifNestedIdx) = 1
_if#v(_ifBlockCount)
			btfsc	freg, bit, fregsel
			goto	_if#v(_ifBlockCount)_ifcase1
			endm


; -------------------------------------------------------------------------------
; IF - ANDIFL
; -------------------------------------------------------------------------------
; Syntax:		andifl freg, cond, lit
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the second register to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
andifl		macro	freg, cond, lit
		if (cond == EQ)
			movf	freg ,W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
			endm

; -------------------------------------------------------------------------------
; IF - ANDIFF
; -------------------------------------------------------------------------------
; Syntax:		andiff freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
andiff		macro		freg1, cond, freg2
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
			endm

; -------------------------------------------------------------------------------
; IF - ANDIFSET
; -------------------------------------------------------------------------------
; Syntax:		andifset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
andifset	macro	freg, bit, fregsel
			btfss	freg, bit, fregsel
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
			endm

; -------------------------------------------------------------------------------
; IF - ANDIFCLR
; -------------------------------------------------------------------------------
; Syntax:		andifclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
andifclr	macro	freg, bit, fregsel
			btfsc	freg, bit, fregsel
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
			endm

; -------------------------------------------------------------------------------
; IF - ORIFL
; -------------------------------------------------------------------------------
; Syntax:		orifl freg, cond, lit
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the literal to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
orifl		macro	freg, cond, lit
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
		if (cond == EQ)
			movf	freg ,W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ORIFF
; -------------------------------------------------------------------------------
; Syntax:		oriff freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
oriff		macro	freg1, cond, freg2
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ORIFSET
; -------------------------------------------------------------------------------
; Syntax:		orifset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
orifset		macro	freg, bit, fregsel
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
			btfss	freg, bit, fregsel
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ORIFCLR
; -------------------------------------------------------------------------------
; Syntax:		orifclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
orifclr		macro	freg, bit, fregsel
			goto	_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
			btfsc	freg, bit, fregsel
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_if#v(_ifNested#v(_ifNestedIdx))_ifcaseskip#v(_ifcaseNested#v(_ifNestedIdx))
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ELSEIFL
; -------------------------------------------------------------------------------
; Syntax:		elseifl freg, cond, lit
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the literal to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
elseifl		macro	freg, cond, lit
			goto	_endif#v(_ifNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
		if (cond == EQ)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg ,W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond = LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ELSIFF
; -------------------------------------------------------------------------------
; Syntax:		elsiff freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
elsiff		macro	freg1, cond, freg2
			goto	_endif#v(_ifNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS,C,ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Invalid condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ELSEIFSET
; -------------------------------------------------------------------------------
; Syntax:		elseifset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
elseifset	macro	freg, bit, fregsel
			goto	_endif#v(_ifNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
			btfss	freg, bit, fregsel
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; ELSEIFCLR
; -------------------------------------------------------------------------------
; Syntax:		elseifclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Affected:		none
; -------------------------------------------------------------------------------
elseifclr	macro	freg, bit, fregsel
			goto	_endif#v(_ifNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
			btfsc	freg, bit, fregsel
			goto _if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx) + 1)
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - OTHERWISE
; -------------------------------------------------------------------------------
; Syntax:		otherwise
; -------------------------------------------------------------------------------
; Affected:		none
; -------------------------------------------------------------------------------
otherwise	macro
			goto	_endif#v(_ifNested#v(_ifNestedIdx))
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
_ifcaseNested#v(_ifNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; IF - ENDI
; -------------------------------------------------------------------------------
; Syntax:		endi
; -------------------------------------------------------------------------------
; Affected:		none
; -------------------------------------------------------------------------------
endi		macro
_if#v(_ifNested#v(_ifNestedIdx))_ifcase#v(_ifcaseNested#v(_ifNestedIdx))
_endif#v(_ifNested#v(_ifNestedIdx))
_ifNestedIdx --
			endm


; -------------------------------------------------------------------------------
; SWITCH
; -------------------------------------------------------------------------------
; Begin loop:	switch, switchf
;   End loop:	endswitch
;     Inners:	casel, casef, casefset, casefclr, default
;  Exit loop:	break
; -------------------------------------------------------------------------------
			variable	_switchBlockCount = 0
			variable	_switchNestedIdx = 0
; -------------------------------------------------------------------------------
; SWITCH
; -------------------------------------------------------------------------------
; Syntax:		switch
; Description: 	begins a switch block.
; Affected:		none
; -------------------------------------------------------------------------------
switch		macro
_switchBlockCount ++
_switchNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_switch#v(_switchBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_switchNested#v(_switchNestedIdx) = _switchBlockCount
			variable	_caseNested#v(_switchNestedIdx) = 1
			goto	_switch#v(_switchBlockCount)_case1
			endm

; -------------------------------------------------------------------------------
; SWITCHF
; -------------------------------------------------------------------------------
; Syntax:		switchf freg
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
; Description: 	begins a switch block moving freg in W register.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
switchf		macro freg
_switchBlockCount ++
_switchNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_switch#v(_switchBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_switchNested#v(_switchNestedIdx) = _switchBlockCount
			variable	_caseNested#v(_switchNestedIdx) = 1
			movf freg, W, BANKED
			goto _switch#v(_switchBlockCount)_case1
			endm

; -------------------------------------------------------------------------------
; SWITCH - CASEL
; -------------------------------------------------------------------------------
; Syntax:		casel lit
; -------------------------------------------------------------------------------
; Arguments:	lit
; Description:	Compares the W register with the lit.
;				If matches instructions following the case macro are executed.
;				Otherwise the next case is tested.
; Affected:		STATUS				
; -------------------------------------------------------------------------------
casel	macro	lit
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
		xorlw	lit
		btfsc	STATUS, Z, ACCESS
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_casematch#v(_caseNested#v(_switchNestedIdx))
		xorlw	lit
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx) + 1)
_switch#v(_switchNested#v(_switchNestedIdx))_casematch#v(_caseNested#v(_switchNestedIdx))
		xorlw		lit
_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_caseNested#v(_switchNestedIdx) ++
		endm

; -------------------------------------------------------------------------------
; SWITCH - CASEF
; -------------------------------------------------------------------------------
; Syntax:		casef freg
; -------------------------------------------------------------------------------
; Arguments:	freg	file register to compare against W
; Description:	Compares the W register with the freg register.
;				If matches instructions following the case macro are executed.
;				Otherwise the next case is tested.
; Affected:		STATUS
; -------------------------------------------------------------------------------
casef	macro	freg
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
		xorwf	freg, W, BANKED
		btfsc	STATUS, Z, ACCESS
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_casematch#v(_caseNested#v(_switchNestedIdx))
		xorwf	freg, W, BANKED
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx) + 1)
_switch#v(_switchNested#v(_switchNestedIdx))_casematch#v(_caseNested#v(_switchNestedIdx))
		xorwf	freg, W, BANKED
_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_caseNested#v(_switchNestedIdx) ++
		endm

; -------------------------------------------------------------------------------
; SWITCH - CASEFSET
; -------------------------------------------------------------------------------
; Syntax:		casefset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	file register to be tested
;				bit		literal value between 0 and 7 indicating the bit to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Description:	Tests the specified bit in register freg.
;				If it is set instructions following the case macro are executed.
;				Otherwise the next case is tested.
; Affected:		none
; -------------------------------------------------------------------------------
casefset	macro	freg, bit, fregsel
			goto	_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
			btfss	freg, bit, fregsel
			goto	_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx) + 1)
_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_caseNested#v(_switchNestedIdx) ++
			endm

; -------------------------------------------------------------------------------
; SWITCH - CASEFCLR
; -------------------------------------------------------------------------------
; Syntax:		casefclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	file register to be tested
;				bit		literal value between 0 and 7 indicating the bit to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Description:	Tests the specified bit in register freg.
;				If it is clear instructions following the case macro are executed.
;				Otherwise the next case is tested.
; Affected:		none
; -------------------------------------------------------------------------------
casefclr	macro	freg, bit, fregsel
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
		btfsc	freg, bit, fregsel
		goto	_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx) + 1)
_switch#v(_switchNested#v(_switchNestedIdx))_caseskip#v(_caseNested#v(_switchNestedIdx))
_caseNested#v(_switchNestedIdx) ++
		endm

; -------------------------------------------------------------------------------
; SWITCH - DEFAULT
; -------------------------------------------------------------------------------
; Syntax:		default
; -------------------------------------------------------------------------------
; Description: 	Block of instructions to execute if none of the other cases held.
; Affected:		none
; -------------------------------------------------------------------------------
default	macro
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
_caseNested#v(_switchNestedIdx) ++
		endm

; -------------------------------------------------------------------------------
; SWITCH - ENDSWITCH
; -------------------------------------------------------------------------------
; Syntax:		endswitch
; -------------------------------------------------------------------------------
; Description: 	Marks the end of a switch block.
; Affected:		none
; -------------------------------------------------------------------------------
endswitch	macro
_switch#v(_switchNested#v(_switchNestedIdx))_case#v(_caseNested#v(_switchNestedIdx))
_endswitch#v(_switchNested#v(_switchNestedIdx))
_switchNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
		endm



; -------------------------------------------------------------------------------
; WHILE
; -------------------------------------------------------------------------------
; Begin loop:	whilefl, whileff, whilefset, whilefclr
;   End loop:	endwhile
;  Exit loop:	break, exitwhile
; -------------------------------------------------------------------------------
			variable	_whileBlockCount = 0
			variable	_whileNestedIdx = 0
; -------------------------------------------------------------------------------
; WHILE - WHILEFL
; -------------------------------------------------------------------------------
; Syntax:		whilefl freg, cond, lit
; Arguments:	freg	the register to be compared
;				cond	the comparision type to use
;				lit		the literal value to compare
; Description: 	Performs a comparison between freg and lit values.
;				If not matches the loop terminates.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
whilefl		macro	freg, cond, lit
_whileBlockCount ++
_whileNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_while#v(_whileBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_whileNested#v(_whileNestedIdx) = _whileBlockCount

		if (cond == EQ)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movlw	lit
			subwf	freg, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg, W, BANKED
			sublw	lit
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg, W, BANKED
			sublw	lit
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movlw	lit
			subwf	freg, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _endwhile#v(_whileNested#v(_whileNestedIdx))
			endm


; -------------------------------------------------------------------------------
; WHILE - WHILEFF
; -------------------------------------------------------------------------------
; Syntax:		whileff freg1, cond, freg2
; -------------------------------------------------------------------------------
; Arguments:	freg1	the first register to be compared
;				cond	the comparision type to use
;				freg2	the second register to compare
; Description:	Performs a comparison of type cond between freg1 and freg2 values.
;				If comparison not matches the loop terminates.
; Affected:		W, STATUS
; -------------------------------------------------------------------------------
whileff		macro	freg1, cond, freg2
_whileBlockCount ++
_whileNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_while#v(_whileBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_whileNested#v(_whileNestedIdx) = _whileBlockCount
		if (cond == EQ)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, Z, ACCESS
		else
		if (cond == NE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, Z, ACCESS
		else
		if (cond == GE)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == GT)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
		if (cond == LE)
			movf	freg1, W, BANKED
			subwf	freg2, W, BANKED
			btfss	STATUS, C, ACCESS
		else
		if (cond == LT)
			movf	freg2, W, BANKED
			subwf	freg1, W, BANKED
			btfsc	STATUS, C, ACCESS
		else
			error "Illegal condition value."
		endif
		endif
		endif
		endif
		endif
		endif
			goto _endwhile#v(_whileNested#v(_whileNestedIdx))
			endm

; -------------------------------------------------------------------------------
; WHILE - WHILEFSET
; -------------------------------------------------------------------------------
; Syntax:		whilefset freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Description:	Tests the specified bit of freg and skip block execution
;				if it is not set.
; Affected:		none
; -------------------------------------------------------------------------------
whilefset	macro	freg, bit, fregsel
_whileBlockCount ++
_whileNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_while#v(_whileBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_whileNested#v(_whileNestedIdx) = _whileBlockCount
			btfss	freg, bit, fregsel
			goto	_endwhile#v(_whileNested#v(_whileNestedIdx))
			endm

; -------------------------------------------------------------------------------
; WHILE - WHILEFCLR
; -------------------------------------------------------------------------------
; Syntax:		whilefclr freg, bit, fregsel
; -------------------------------------------------------------------------------
; Arguments:	freg	the register to be tested
;				bit		a literal value between 0 and 7 specifying the bit
;						to be tested
;				fregsel	file register selection type: ACCESS oer BANKED
; Description:  Tests the specified bit of freg and skip block execution
;				if it is set.
; Affected:		none
; -------------------------------------------------------------------------------
whilefclr	macro	freg, bit, fregsel
_whileBlockCount ++
_whileNestedIdx ++
_breakCount ++
_breakNestedIdx ++
_while#v(_whileBlockCount)
			variable	_breakNested#v(_breakNestedIdx) = _breakCount
			variable	_whileNested#v(_whileNestedIdx) = _whileBlockCount
			btfsc	freg, bit, fregsel
			goto	_endwhile#v(_whileNested#v(_whileNestedIdx))
			endm

; -------------------------------------------------------------------------------
; WHILE - EXITWHILE
; -------------------------------------------------------------------------------
; Syntax:		exitwhile
; Description:  Exit from the innermost while block.
; Affected:		none
; -------------------------------------------------------------------------------
exitwhile	macro
			goto	_endwhile#v(_whileNested#v(_whileNestedIdx))
			endm

; -------------------------------------------------------------------------------
; WHILE - ENDWHILE
; -------------------------------------------------------------------------------
; Syntax:		endwhile
; -------------------------------------------------------------------------------
; Description: 	Marks the end of a while block.
; Affected:		none
; -------------------------------------------------------------------------------
endwhile	macro
			goto _while#v(_whileBlockCount)
_endwhile#v(_whileNested#v(_whileNestedIdx))
_whileNestedIdx --
_break#v(_breakNested#v(_breakNestedIdx))
_breakNestedIdx --
			endm


; -------------------------------------------------------------------------------
; BREAK
; -------------------------------------------------------------------------------
; Syntax:		break
; -------------------------------------------------------------------------------
; Description:	Exits from the current block.
;				Can be unsed as generic exit from any loop type.
; Affected:		none
; -------------------------------------------------------------------------------
break		macro
			goto _break#v(_breakNested#v(_breakNestedIdx))
			endm
